﻿using AdminApi.Extension.Permission.Attributes;
using AdminApi.Extension.Permission.Model;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;

namespace AdminApi.Extension.Permission
{
    public class PressionManager
    {
        private static TreeNodeDto root { get; set; }

        private static List<PermissionMenuInfo> perssionMenuInfos { get; set; }
        internal static void Init(Type type)
        {
            var cs = type.Assembly.GetTypes().Where(i => i.IsSubclassOf(typeof(ControllerBase)));

            List<PermissionMenuInfo> perssionMenuInfos = new List<PermissionMenuInfo>();
            foreach (var item in cs)
            {
                foreach (var method in item.GetMethods())
                {
                    var menuAttr = (PerssionMenuAttribute)method.GetCustomAttributes(typeof(PerssionMenuAttribute), false).FirstOrDefault();
                    var route = (RouteAttribute)method.GetCustomAttributes(typeof(RouteAttribute), false).FirstOrDefault();
                    if (menuAttr != null)
                    {
                        PermissionMenuInfo perssionMenuInfo = new PermissionMenuInfo();
                        perssionMenuInfo.MenuType = menuAttr.MenuType;
                        perssionMenuInfo.Index = menuAttr.Index;
                        perssionMenuInfo.MetadataToken = method.MetadataToken;
                        perssionMenuInfo.MethodInfo = method;
                        perssionMenuInfo.Name = menuAttr.Name;
                        perssionMenuInfo.ParentPath = menuAttr.ParentPath;
                        perssionMenuInfo.Url = route.Template;
                        perssionMenuInfo.ID = perssionMenuInfo.Url;
                        perssionMenuInfos.Add(perssionMenuInfo);
                    }
                }
            }
            TreeNodeDto root = new TreeNodeDto();
            root.Name = "Root";
            root.HasChilds = true;
            root.PerssionMenuInfo = null;
            root.MenuType = MenuType.分组菜单;
            root.Childs = new List<TreeNodeDto>();
            root.Settings = new List<TreeNodeDto>();

            foreach (var item in perssionMenuInfos.OrderBy(i => (int)i.MenuType))
            {
               
                var parent = ParentNode(root, item);
                var node = BulidNode(item);
                node.Parent = parent;
                if ((int)node.MenuType == 1)
                {
                    if (!string.IsNullOrWhiteSpace(node.Index) && node.Index.IndexOf("/") > -1)
                    {
                        string[] ls = node.Index.Split('/');
                        node.Index = ls[ls.Length - 1];
                        if (string.IsNullOrWhiteSpace(parent.Index))
                        {
                            parent.Index = ls[ls.Length - 2];
                        }
                    }
                }
                if ((int)node.MenuType > 1) {
                    parent.Settings.Add(node);
                }
                else
                {
                    parent.Childs.Add(node);
                }
            }

            PressionManager.root = root;
            PressionManager.perssionMenuInfos = perssionMenuInfos;
        }

        internal static PermissionMenuInfo GetPerssionMenuInfoByMetadataToken(int mtoken)
        {
            return perssionMenuInfos.FirstOrDefault(i => i.MetadataToken == mtoken);
        }

        private static TreeNodeDto ParentNode(TreeNodeDto root, PermissionMenuInfo perssionMenuInfo)
        {
            var parentArr = perssionMenuInfo.ParentPath.Split('-');
            TreeNodeDto lastNode = root;
            for (int i = 0; i < parentArr.Length; i++)
            {               
                var thisNode = lastNode.Childs.Where(j => j.Name.Equals(parentArr[i])).FirstOrDefault();
                if (thisNode == null)
                {
                    
                    thisNode = BulidMenuNode(parentArr[i]);
                    if ((int)thisNode.MenuType == 0)
                    {
                        if (Enum.IsDefined(typeof(SIndexType), thisNode.Name.Trim(' ')))
                        {
                            var iss = Enum.Parse(typeof(SIndexType), thisNode.Name.Trim(' '));
                            SIndexType sIndex = (SIndexType)iss;
                            thisNode.Index = (Convert.ToInt32(sIndex)).ToString();
                        }
                    }
                    thisNode.Parent = lastNode;
                    lastNode.Childs.Add(thisNode);
                }

                lastNode = thisNode;

                //if (lastNode.MenuType == MenuType.分组菜单 || lastNode.MenuType == MenuType.菜单列表 || lastNode.MenuType == MenuType.查询)
                //{
                //    if (lastNode.Childs==null)
                //    {
                //        lastNode.Childs = new List<TreeNodeDto>();
                //        lastNode.HasChilds = true;
                //    }
                //}
            }
            if (lastNode.Settings == null)
            {
                lastNode.Settings = new List<TreeNodeDto>();
            }


            return lastNode;
        }

        internal static TreeNodeDto GetRolePerssion(ISet<string> set)
        {
            var result = perssionMenuInfos.Where(i => set.Contains(i.ID));

            var root = (TreeNodeDto)PressionManager.root.Clone();

            foreach (var item in result)
            {
                root.PickUpID(item.ID);
            }

            return root;
        }


        internal static TreeNodeDto GetAdminMenus(ISet<string> adminPressionSet)
        {
            if (adminPressionSet.Contains("*")) return PressionManager.root;

            var result = perssionMenuInfos.Where(i => adminPressionSet.Contains(i.ID));

            TreeNodeDto root = new TreeNodeDto();
            root.Name = "Root";
            root.HasChilds = true;
            root.PerssionMenuInfo = null;
            root.MenuType = MenuType.分组菜单;
            root.Childs = new List<TreeNodeDto>();
            root.Settings = new List<TreeNodeDto>();

            foreach (var item in result.OrderBy(i => (int)i.MenuType))
            {
                var parent = ParentNode(root, item);
                var node = BulidNode(item);
                if ((int)node.MenuType > 1&& (int)parent.MenuType==1) { parent.Settings.Add(node); }
                else
                {
                    parent.Childs.Add(node);
                }
                if ((int)node.MenuType == 1)
                {
                    if (!string.IsNullOrWhiteSpace(node.Index) && node.Index.IndexOf("/") > -1)
                    {
                        string[] ls = node.Index.Split('/');
                        node.Index = ls[ls.Length - 1];
                        if (string.IsNullOrWhiteSpace(parent.Index))
                        {
                            parent.Index = ls[ls.Length - 2];
                        }
                    }
                }

            }

            return root;
        }

        private static TreeNodeDto BulidMenuNode(String name)
        {
            TreeNodeDto root = new TreeNodeDto();
            root.Name = name;
            root.MenuType = MenuType.分组菜单;
            if (root.MenuType == MenuType.分组菜单)
            {
                root.HasChilds = true;
                root.Childs = new List<TreeNodeDto>();
            }
            root.PerssionMenuInfo = null;

            return root;
        }


        private static TreeNodeDto BulidNode(PermissionMenuInfo perssionMenuInfo)
        {
            TreeNodeDto root = new TreeNodeDto();
            root.Name = perssionMenuInfo.Name;
            root.Index = perssionMenuInfo.Index;
            root.MenuType = perssionMenuInfo.MenuType;
            if (root.MenuType == MenuType.菜单列表)
            {
                root.HasChilds = true;
                if (root.Settings == null)
                {
                    root.Settings = new List<TreeNodeDto>();
                }             
            }            
            root.PerssionMenuInfo = perssionMenuInfo;

            return root;
        }

    }
}